package ee.fj.util.assertion;

/**
 * All purpose string based assertion.
 * Supported : && || == != >, >=, <= <, =~(like -uses regular expression) !=~
 * Key fields should be dot-separated. If first null value met returns null.
 * java.util.Map and java.util.List supported. Just use as dot-separated fields.
 * @author Margus Rebane
*/

public abstract class Assertion {
	public static final boolean DEFAULT_CONDITION = Boolean.FALSE;

	private final boolean reverse;

	public Assertion(boolean reverse) {
		this.reverse = reverse;
	}
	public Assertion() {
		this(DEFAULT_CONDITION);
	}

	public final boolean satisfies(Object value) throws AssertionException {
		boolean retVal = satisfiesInner(value);
		if (reverse)
			return !retVal;
		return retVal;
	}

	protected abstract boolean satisfiesInner(Object value) throws AssertionException;

	public static Assertion getInstance(String val) {
		int i = val.lastIndexOf("&&");
		if (i < 0) i = val.lastIndexOf("||");
		if (i > -1) {
			Assertion retVal = null;
			String last_l = null;
			while (i > -1) {
				if (retVal != null) {
					retVal = new AssertionChain(getInstance(val.substring(i + 2)),
							retVal,
							last_l.equals("&&") ? AssertionChain.ConditionType.and : AssertionChain.ConditionType.or);
				} else {
					retVal = getInstance(val.substring(i + 2));
				}
				last_l = val.substring(i, i+2);
				val = val.substring(0, i);
				i = val.lastIndexOf("&&");
				if (i < 0) i = val.lastIndexOf("||");
			}
			if (val.length() > 0) {
				if (retVal != null) {
					retVal = new AssertionChain(getInstance(val), retVal, last_l.equals("&&") ? AssertionChain.ConditionType.and : AssertionChain.ConditionType.or);
				} else {
					retVal = getInstance(val);
				}
			}
			return retVal;
		}

		i = val.indexOf("!=~");
		if (i > 0)
			return new FieldAssertion(val.substring(0, i), new RegexpAssertion(val.substring(i+3)), Boolean.TRUE);

		i = val.indexOf("=~");
		if (i > 0)
			return new FieldAssertion(val.substring(0, i), new RegexpAssertion(val.substring(i+2)));

		i = val.indexOf("!=");
		if (i > 0)
			return new FieldAssertion(val.substring(0, i), new ComparableAssertion(val.substring(i+2), ComparableAssertion.Type.eq, Boolean.TRUE));

		i = val.indexOf(">=");
		if (i > 0)
			return new FieldAssertion(val.substring(0, i), new ComparableAssertion(val.substring(i+2), ComparableAssertion.Type.ge, Boolean.TRUE));

		i = val.indexOf("<=");
		if (i > 0)
			return new FieldAssertion(val.substring(0, i), new ComparableAssertion(val.substring(i+2), ComparableAssertion.Type.ge));

		i = val.indexOf(">");
		if (i > 0)
			return new FieldAssertion(val.substring(0, i), new ComparableAssertion(val.substring(i+1), ComparableAssertion.Type.gt, Boolean.TRUE));

		i = val.indexOf("<");
		if (i > 0)
			return new FieldAssertion(val.substring(0, i), new ComparableAssertion(val.substring(i+1), ComparableAssertion.Type.gt));


		i = val.indexOf("=");
		if (i > 0)
			return new FieldAssertion(val.substring(0, i), new ComparableAssertion(val.substring(i+1), ComparableAssertion.Type.eq));

		if (val.startsWith("!"))
			return new FieldAssertion(val.substring(1), new ValueExistsAssertion() , Boolean.FALSE);


		return new FieldAssertion(val, new ValueExistsAssertion());
	}
}
